//-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   raster
//File Name     :   block_scan.v
//Module name   :   block scan
//Full name     :   block scan for overlap block
//
//Author        :   zha daolu
//Email         :   
//Data          :   2020/6/1
//Version       :   V1.00
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//-----------------------------  
module block_scan
(
    input					clk,              //input clock
    input					rst_n,            //input reset, low active
    input					busy,             //input next stage busy
    input					block_start,      //input scan start
    input signed[47:0]		a0,               //input ee parameter
    input signed[47:0]		b0,               //input ee parameter
    input signed[47:0]		a1,               //input ee parameter
    input signed[47:0]		b1,               //input ee parameter
    input signed[47:0]		a2,               //input ee parameter
    input signed[47:0]		b2,               //input ee parameter
    input signed[95:0]		ee0_int,          //input ee0 for tile left-bottom corner
    input signed[95:0]		ee1_int,          //input ee1 for tile left-bottom corner
    input signed[95:0]		ee2_int,          //input ee2 for tile left-bottom corner
    output [7:0]			position_pix,     //ouput 2x2 block
    output					pix_en,           //output valid
    output					block_scan_end    //output scan done
);

//FSM
localparam		IDLE = 3'd0;
localparam		STEP0 = 3'd1;
localparam		STEP1 = 3'd2;
localparam		STEP2 = 3'd3;
localparam		STEP3 = 3'd4;


reg[2:0]			cur_state;
reg[2:0]			next_state;

wire				state_ready;
wire				fifo_rd;

//8x8 block
reg[1:0]			position_8;
reg					position_8_en;

reg[5:0]			position_fifo;
reg[1:0]			scale_fifo;


wire				flag_8_fifo_rd;
wire				flag_8_fifo_wr;
wire				flag_8_fifo_full;
wire				flag_8_fifo_empty;
wire[5:0]			flag_8_fifo_dataout;
wire[5:0]			flag_8_fifo_datain;


wire				flag_4_fifo_rd;
wire				flag_4_fifo_wr;
wire				flag_4_fifo_full;
wire				flag_4_fifo_empty;
wire[5:0]			flag_4_fifo_dataout;
wire[5:0]			flag_4_fifo_datain;
	
reg[5:0]			flag_8_position_temp;
reg[5:0]			flag_4_position_temp;
reg					flag_en;

reg[5:0]			position_coor;
reg[1:0]			scale_coor;
wire[1:0] 			sym0 = {a0[47],b0[47]};
wire[1:0] 			sym1 = {a1[47],b1[47]};	
wire[1:0] 			sym2 = {a2[47],b2[47]};		

wire[5:0]			lin_x0;
wire[5:0]           lin_y0;
wire[5:0]           lin_x1;
wire[5:0]           lin_y1;
wire[5:0]           lin_x2;
wire[5:0]           lin_y2;
reg					xy_en;
wire				overlap;
wire[5:0]			position_out;
wire[1:0]			scale_out;

wire				block_overlap_busy;

//8x8 block position traversal 
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			position_8		<= 2'b0;
			position_8_en   <= 1'b0;
		end
	else if(block_start)
		begin
			position_8		<= 2'b0;
			position_8_en	<= 1'b1;
		end
	else if(position_8 == 2'h3)
		begin
			position_8		<= 2'b0;
			position_8_en	<= 1'b0;	
		end
	else if(position_8_en)
		begin
			position_8      <= position_8 + 1'b1;
			position_8_en   <= 1'b1;
		end
end

//fsm, indicate which block (0-3)
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		cur_state	<= IDLE;
	else
		cur_state	<= next_state;
end

always@(*)
begin
	case(cur_state)
		IDLE:	begin	if(!busy&&state_ready)
							next_state = STEP0;
						else
							next_state = IDLE;
				end
		
		STEP0:	begin	if(!busy)
							next_state = STEP1;
						else 
							next_state = STEP0;		
				end
		
		STEP1:	begin	if(!busy)
		                	next_state = STEP2;
		                else 
			            	next_state = STEP1;
				end
				
		STEP2:	begin	if(!busy)
                        	next_state = STEP3;
                        else 
                        	next_state = STEP2;
				end
				
		STEP3:	begin	if(!busy&&state_ready)
							next_state = STEP0;
						else if(!busy&&!state_ready)
							next_state = IDLE;
						else
							next_state = STEP3;
				end
		default:
			next_state = STEP0;
	endcase
end
						
//register position for 8x8 block and 4x4 block																										
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			position_fifo	<= 6'b0;
			scale_fifo		<= 2'b0;
		end
	else if(flag_4_fifo_rd)
		begin
			position_fifo	<= flag_4_fifo_dataout;
			scale_fifo		<= 2'b01;		
		end
	else if(flag_8_fifo_rd)
		begin
			position_fifo	<= flag_8_fifo_dataout;
			scale_fifo		<= 2'b10;		
		end
end
																									
//STEP0-3 = block 0-3
//0:left bottom
//1:right bottom
//2:left top
//3:right top
always@(*)
begin
	case(cur_state)
		STEP0:	begin
					if(!busy)
						begin
							flag_8_position_temp = position_fifo;
							flag_4_position_temp = position_fifo;
							flag_en				 = 1'b1;				
						end
					else
						begin
							flag_8_position_temp = position_fifo;
							flag_4_position_temp = position_fifo;
						    flag_en				 = 1'b0;				
						end
				end
				
		STEP1:	begin
					if(!busy)
				    	begin
				    		flag_8_position_temp = {position_fifo[5:4],4'b0100};
		            		flag_4_position_temp = {position_fifo[5:2],2'b01};
		            		flag_en				 = 1'b1;				
		            	end
		            else
		            	begin
		            		flag_8_position_temp = {position_fifo[5:4],4'b0100};
		            		flag_4_position_temp = {position_fifo[5:2],2'b01};
		            	    flag_en				 = 1'b0;				
						end
				end
		
		STEP2:  begin
	            	if(!busy)
	                	begin
	                		flag_8_position_temp = {position_fifo[5:4],4'b1000};
	                		flag_4_position_temp = {position_fifo[5:2],2'b10};
	                		flag_en				 = 1'b1;				
	                	end
	                else
	                	begin
	                		flag_8_position_temp = {position_fifo[5:4],4'b1000};
	                		flag_4_position_temp = {position_fifo[5:2],2'b10};
	                	    flag_en				 = 1'b0;				
	            		end
	            end
				
		STEP3:	begin
	            	if(!busy)
	                	begin
	                		flag_8_position_temp = {position_fifo[5:4],4'b1100};
	                		flag_4_position_temp = {position_fifo[5:2],2'b11};
	                		flag_en				 = 1'b1;				
	                	end
	                else
	                	begin
	                		flag_8_position_temp = {position_fifo[5:4],4'b1100};
	                		flag_4_position_temp = {position_fifo[5:2],2'b11};
	                	    flag_en				 = 1'b0;				
	            		end
	            end	
		default:begin
						flag_8_position_temp = 8'b0;
                        flag_4_position_temp = 8'b0;
                        flag_en				 = 1'b0;				
				end
	endcase
end																									

//scale indicate block size
//11: 8x8
//10: 4x4
//01: 2x2
//00: reservced
always@(*)
begin
	if(position_8_en)
		begin
			position_coor = {position_8,4'b0000};
			scale_coor	= 2'b11;
		end
	else if(scale_fifo == 2'b10)
		begin
			position_coor = flag_8_position_temp;	
			scale_coor	  = 2'b10;
		end
	else if(scale_fifo == 2'b01)
		begin
			position_coor = flag_4_position_temp;
			scale_coor 	  = 2'b01;		
		end
	else
		begin
			position_coor = flag_4_position_temp;
			scale_coor 	  = 2'b01;		
		end
end


//calculate start flag
always@(*)
begin
	if(position_8_en)
		xy_en = 1'b1;
	else
		xy_en = flag_en;
end

//calculate max ee coordinate for a block with size scale coor
coor_cnt  uut_coor_cnt
(
    .clk	 (clk          ),
    .rst_n	 (rst_n        ),
    .busy(busy),
    .position(position_coor),
    .scale   (scale_coor   ),
    .sym0    (sym0    	   ),
    .sym1    (sym1    	   ),
    .sym2    (sym2    	   ),
    .lin_x0  (lin_x0  	   ),
    .lin_y0  (lin_y0  	   ),
    .lin_x1  (lin_x1  	   ),
    .lin_y1  (lin_y1  	   ),
    .lin_x2  (lin_x2  	   ),
    .lin_y2  (lin_y2  	   )
);


reg[7:0]	position_coor_ff1;
reg[1:0]	scale_coor_ff1;
reg			xy_en_ff1;

always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			position_coor_ff1 <= 6'b0;
			scale_coor_ff1 <= 2'b0;
			xy_en_ff1 <= 1'b0;	
		end
	else if(!busy)
		begin
			position_coor_ff1 <= position_coor;
		    scale_coor_ff1 <= scale_coor;
		    xy_en_ff1 <= xy_en;					
		end
end

//block overlap 
//
block_overlap  uut_block_overlap
(                      
    .clk         (clk         ),
    .rst_n       (rst_n       ),
    .busy        (busy        ),
    .position_in (position_coor_ff1 ),
    .scale_in    (scale_coor_ff1    ),
    .lin_x0      (lin_x0      ),
    .lin_y0      (lin_y0      ),
    .lin_x1      (lin_x1      ),
    .lin_y1      (lin_y1      ),
    .lin_x2      (lin_x2      ),
    .lin_y2      (lin_y2      ),
    .xy_en       (xy_en_ff1       ),
    .a0          (a0          ),
    .b0          (b0          ),
    .a1          (a1          ),
    .b1          (b1          ),
    .a2          (a2          ),
    .b2          (b2          ),
    .ee0_int     (ee0_int     ),
    .ee1_int     (ee1_int     ),
    .ee2_int     (ee2_int     ),
    .overlap     (overlap     ),
    .position_out(position_out),
    .scale_out   (scale_out   ),
    .block_overlap_busy(block_overlap_busy)
);

//flag_8_fifo for 8x8 overlap block
fifo#(
	.DWIDTH(6),
	.DSIZE(4)
	)  flag_8_fifo
(
    .SCAN_mode(1'b0),  
    .datain     (flag_8_fifo_datain),
    .rd         (flag_8_fifo_rd),
    .wr         (flag_8_fifo_wr),
    .rst_n      (rst_n),
    .clk        (clk),
    .almost_full(),
    .dataout    (flag_8_fifo_dataout),
    .full       (flag_8_fifo_full),
    .empty      (flag_8_fifo_empty)
);


//flag_4_fifo for 4x4 overlap block
fifo#(
	.DWIDTH(6),
	.DSIZE(3)
	)  flag_4_fifo
(
    .SCAN_mode(1'b0), 
    .datain     (flag_4_fifo_datain),
    .rd         (flag_4_fifo_rd),
    .wr         (flag_4_fifo_wr),
    .rst_n      (rst_n),
    .clk        (clk),
    .almost_full(),
    .dataout    (flag_4_fifo_dataout),
    .full       (flag_4_fifo_full),
    .empty      (flag_4_fifo_empty)
);


assign	fifo_rd			  	= (next_state == STEP0) && !busy;        //read fifo when fsm is ready for new traversal
assign  flag_8_fifo_datain	= position_out;                          //  fifo wr data and output data
assign	flag_4_fifo_datain	= position_out;                          //         position out 
assign	position_pix	  	= position_out;                          //
assign	flag_8_fifo_wr	  	= overlap && (scale_out == 2'b11);       //write overlap 8x8 block to flag8 fifo
assign  flag_4_fifo_wr	 	= overlap && (scale_out == 2'b10);       //write overlap 4x4 block to flag4 fifo
assign	pix_en				= overlap && (scale_out == 2'b01);       //output overlap 2x2 block
assign	flag_4_fifo_rd		= fifo_rd && !flag_4_fifo_empty;         //read flag 4 fifo when flag4 fifo is not empty
assign	flag_8_fifo_rd		= fifo_rd && flag_4_fifo_empty && !flag_8_fifo_empty;  //read flag 8 fifo when flag4 fifo empty and flag8 fifo not empty
assign	state_ready			= !position_8_en && (!flag_8_fifo_empty || !flag_4_fifo_empty);  //ready for new traversal

assign	block_scan_end		=  flag_4_fifo_empty && flag_8_fifo_empty && (!block_overlap_busy) && ~xy_en;  //

endmodule









